package com.duojuhe.common.component.thread;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 任务顺序线程处理Service
 * 此方法保证针对同一个任务操作一定是顺序执行的
 *
 *
 * @date 2018/8/10.
 */
@Slf4j
@Component
public class ThreadProcessManager {
    private List<ThreadPoolExecutor> poolExecutorList;
    private ThreadFactory factory = (new ThreadFactoryBuilder()).setNameFormat("Process-Thread" + "-pool-%d").build();
    private int TASK_THREAD_NUM = 10;

   /* @PostConstruct*/
    public void initProcessThreadPool() {
        this.poolExecutorList = new ArrayList<>();
        for (int i = 0; i < TASK_THREAD_NUM; i++) {
            ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(), factory);
            poolExecutorList.add(threadPoolExecutor);
        }
        log.info("初始化任务线程结束,共初始化{}个线程池", TASK_THREAD_NUM);
    }

    /**
     * 任务调度，每次相同的taskId都会进去同一个线程池
     *
     * @param taskId   任务编号
     * @param runnable 任务
     */
    public void process(String taskId, Runnable runnable) {
        this.getThreadPoolExecutor(taskId).execute(runnable);
    }

    /**
     * 任务调度，每次相同的taskId都会进去同一个线程池且有响应值
     *
     * @param taskId   任务编号
     * @param runnable 任务
     */
    public Future processWithResult(String taskId, Callable<Object> runnable) {
        return this.getThreadPoolExecutor(taskId).submit(runnable);
    }

    /**
     * 通过一致性算法，算出该任务编号对应的线程池，确保以后每次都走此线程池
     *
     * @param taskId   任务编号
     * @return
     */
    private ThreadPoolExecutor getThreadPoolExecutor(String taskId) {
        try {
            if (StringUtils.isBlank(taskId)){
                return poolExecutorList.get(0);
            }
            int hashCode = taskId.hashCode();
            int index = Math.abs(hashCode % TASK_THREAD_NUM);
            return poolExecutorList.get(index);
        } catch (Exception e) {
            log.error("【一致性算法】根据任务ID计算索引异常,taskId={}, maxSize={}", taskId,TASK_THREAD_NUM);
            return poolExecutorList.get(0);
        }
    }


    public static void main(String[] args) {
      /*  //判断代理ID是否存在
        Future future = processService.processWithResult(agentUser.getAgentId(), () -> {
            // spring无法处理thread的事务，声明式事务无效
            TransactionStatus status = threadTransactionManager.getTransactionStatus(); // 获得事务状态
            try {
                AgentRealName agentRealName =  agentRealNameService.queryAgentRealNameInfoById(agentUser.getAgentId());
                if(!SystemEnum.REAL_NAME_STATUS.PASS.getKey().equals(agentRealName.getStatus())){
                    // 提交事务
                    threadTransactionManager.commit(status);
                    return ServiceResult.fail(ErrorCodes.CHECK_REAL_NAME);
                }
                threadTransactionManager.commit(status); // 提交事务
                return ServiceResult.ok(ErrorCodes.SUCCESS);
            } catch (Exception e) {
                threadTransactionManager.rollback(status); // 回滚事务
                log.error("绑定银行卡出现异常", e);
                return ServiceResult.fail(ErrorCodes.FAIL);
            }
        });
        return (ServiceResult) future.get();*/
    }
}
